Fork me on GitHub

『BZOJ 1935』[SHOI2007]Tree 园丁的烦恼

Problem

题目描述 Description
很久很久以前,在遥远的大陆上有一个美丽的国家。统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草。有一天国王漫步在花园里,若有所思,他问一个园丁道:
“最近我在思索一个问题,如果我们把花坛摆成六个六角形,那么……”
“那么本质上它是一个深度优先搜索,陛下”,园丁深深地向国王鞠了一躬。
“嗯……我听说有一种怪物叫九头蛇,它非常贪吃苹果树……”
“是的,显然这是一道经典的动态规划题,早在N元4002年我们就已经发现了其中的奥秘了,陛下”。
“该死的,你究竟是什么来头?”
“陛下息怒,干我们的这行经常莫名其妙地被问到和OI有关的题目,我也是为了预防万一啊!”
王者的尊严受到了伤害,这是不可容忍的。看来一般的难题是难不倒这位园丁的,国王最后打算用车轮战来消耗他的实力:

“年轻人,在我的花园里的每一棵树可以用一个整数坐标来表示,一会儿,我的骑士们会来轮番询问你某一个矩阵内有多少树,如果你不能立即答对,你就准备走人吧!”说完,国王气呼呼地先走了。

这下轮到园丁傻眼了,他没有准备过这样的问题。所幸的是,作为“全国园丁保护联盟”的会长——你,可以成为他的最后一根救命稻草。

输入描述 Input Description
文件的第一行有两个整数n,m(0≤n≤500000,1≤m≤500000)。n代表皇家花园的树木的总数,m代表骑士们询问的次数。
文件接下来的n行,每行都有两个整数xi,yi,代表第i棵树的坐标(0≤xi,yi≤10000000)。
文件的最后m行,每行都有四个整数aj,bj,cj,dj,表示第j次询问,其中所问的矩形以(aj,bj)为左下坐标,以(cj,dj)为右上坐标。

输出描述 Output Description
共输出m行,每行一个整数,即回答国王以(aj,bj)和(cj,dj)为界的矩形里有多少棵树。

样例输入 Sample Input
3 1
0 0
0 1
1 0
0 0 1 1

样例输出 Sample Output
3

数据范围及提示 Data Size & Hint
0≤n≤500000,1≤m≤500000

Solution

所以说,这道题目第一眼看上去是二维树状数组
但是再看看数据范围太大了,想到离散化
离散化处理还是比较妙的,我们离线找答案,按横坐标排序依次处理。
不能用二维树状数组做(尽管带差分然而仍然会炸),于是就直接按两倍的N建立树状数组来做就行了。
代码跑得很快,洛谷632ms, 暂时Rank1;
然而BZOJ的老机子实在是巨慢无比,居然跑了3300ms左右
结果就Rank n了。
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#define MAXN 2500000 + 5

using namespace std;
int N, M;
struct node
{
int x, y, flag, num;
};
node a[MAXN];
inline bool cmp(node q, node w)
{
if (q.x < w.x) return true;
else
if (q.x == w.x) return q.num < w.num;
return false;
}
int t[MAXN], ans[MAXN];
inline int lowbit(int x)
{
return x & (-x);
}
inline void add(int k)
{
for (register int i = k; i <= 2 * N; i += lowbit(i)) ++t[i];
}
inline int query(int k)
{
int res = 0;
for (register int i = k; i > 0; i -= lowbit(i))
res += t[i];
return res;
}
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _read()
{
int a = 0, f = 1;
static char c = nc();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = nc();
}
while (c >= '0' && c <= '9')
{
a = a * 10 + c - '0';
c = nc();
}
return a * f;
}

int main(int argc, char **argv)
{
N = _read(), M = _read();
for (register int i = 1; i <= N; ++i)
{
a[i].x = _read(), a[i].y = _read();
a[i].x++, a[i].y++;
a[i].num = a[i].num = 0;
}
int now = N;
for (register int i = 1; i <= M; ++i)
{
int x1, x2, y1, y2;
x1 = _read(), y1 = _read(), x2 = _read(), y2 = _read();
a[++now] = (node){x1, y1, 1, i};
a[++now] = (node){x2 + 1, y2 + 1, 1, i};
a[++now] = (node){x1, y2 + 1, -1, i};
a[++now] = (node){x2 + 1, y1, -1, i};
}
sort(a + 1, a + now + 1, cmp);
for (register int i = 1; i <= now; ++i)
if (!a[i].num)
{
add(a[i].y);
}
else
{
ans[a[i].num] += a[i].flag * query(a[i].y);
}
for (register int i = 1; i <= M; ++i)
printf("%d\n", ans[i]);
return 0;
}

话说为了Rank1我tm第一次写了fread的读入优化啊。。

-------------本文结束了哦感谢您的阅读-------------